#include "program_slicing.hpp"

program_slicing::program_slicing(const CFGvisitorFlatInfo& _flat, const ReachingDefs& _rd)
: flat(_flat), rd(_rd) {
	this->visited.resize(flat.labels.size(), false); // no labels visited yet
}

void program_slicing::pslice(label_t ell0) {
	this->mark_as_visited(ell0);
	this->S.insert(ell0);

	set<label_t> L;

	const RD& RD_entry = rd.MFP_entry(ell0);
	for (RD::const_iterator it = RD_entry.begin(); it != RD_entry.end(); ++it) {
		const RD_element& x_ell = *it;
		const string& x = x_ell.first;
		const label_t& ell = x_ell.second;

		if (this->used(ell0).count(x)) {
			L.insert(ell);
		}
	}

	set<label_t> A = this->get_nested_If_and_Whiles(ell0);

	set<label_t> LUA;
	LUA = L;
	LUA.insert(A.begin(), A.end());

	for (set<label_t>::iterator it = LUA.begin(); it != LUA.end(); ++it) {
		label_t ell = *it;
		if (!this->has_been_visited(ell)) {
			this->pslice(ell);
		}
	}
}

set<label_t> program_slicing::getS() const {
	return this->S;
}

void program_slicing::mark_as_visited(label_t ell) {
	this->visited[ell] = true;
}

bool program_slicing::has_been_visited(label_t ell) {
	return this->visited[ell];
}

set<string/*var*/> program_slicing::used(label_t ell) const {
	ASTvisitorUses u;
	return u.convert(this->getPayload(ell));
}

ASTnode* program_slicing::getPayload(label_t ell0) const {
	return this->getPayload(flat.labels[ell0]);
}

ASTnode* program_slicing::getPayload(CFGvertex *n) const {
	ASTnode *a = NULL;
	if (TRY_TYPE(box*, b, n)) {
		a = b->payload;
	}
	if (TRY_TYPE(diamond*, d, n)) {
		a = d->condition;
	}
	assert(a);
	return a;
}

set<label_t> program_slicing::get_nested_If_and_Whiles(label_t ell0) const {
	set<label_t> A;
	ASTnode *a = this->getPayload(ell0);

	while (a != NULL) {
		if (TRY_TYPE(control_statement*, ctr, a->parent)) {
			assert(ctr->cond);
			CFGvertex *n = flat.reverse_payload.at(ctr->cond);
			assert(dynamic_cast<diamond*>(n));
			A.insert(n->label());	
		}
		a = a->parent;
	}
	return A;
}
